use crate::core::error::operation_error::OperationError;
use crate::core::operation::Operation;
use crate::core::path_type::TypedPath;
use crate::core::path_type::TypedPath::Contextual;
use crate::core::step_context::StepContext;
use crate::core::util::Util;
use std::fmt::Debug;
use std::sync::Arc;
use strum_macros::{Display, EnumString};
use tokio::fs::OpenOptions;
use tonic::async_trait;

use super::build_target::BuildTarget;

pub struct Unity {
    build_target: BuildTarget,
    project_path: TypedPath,
    execute_method: String,
    log_file_path: TypedPath,
    args: Vec<String>,
}

impl Unity {
    pub fn new(
        build_target: BuildTarget,
        project_path: TypedPath,
        execute_method: String,
        log_file_path: Option<TypedPath>,
        args: Option<Vec<String>>,
    ) -> Self {
        Unity {
            build_target,
            project_path,
            execute_method,
            log_file_path: log_file_path.unwrap_or(Contextual(String::from("log.txt"))),
            args: args.unwrap_or(vec![]),
        }
    }
}

#[async_trait]
impl Operation for Unity {
    async fn run(&mut self, context: Arc<StepContext>) -> Result<(), OperationError> {
        let path = match &self.project_path {
            TypedPath::Normal(p) => p.clone(),
            Contextual(s) => context.job_context().path().join(s),
        };

        let log_file_path = match &self.log_file_path {
            TypedPath::Normal(p) => p.clone(),
            Contextual(s) => context.job_context().path().join(s),
        };

        let target = self.build_target.to_string();
        let mut args = vec![
            "-nographics",
            "-batchmode",
            "-quit",
            "-buildTarget",
            &target,
            "-projectPath",
            path.to_str().unwrap(),
            "-executeMethod",
            self.execute_method.as_str(),
            "-logFile",
            log_file_path.to_str().unwrap(),
        ];

        for s in self.args.iter() {
            args.push(s);
        }

        let (s, r) = tokio::sync::oneshot::channel();
        let f = OpenOptions::new()
            .read(true)
            .open(&log_file_path)
            .await
            .unwrap();
        let log_handle = tokio::spawn(Util::log_line_continuously(f, context.clone(), r));

        context
            .run_cmd(
                r"C:\Program Files\Unity\Hub\Editor\2022.3.34f1c1\Editor\Unity.exe",
                args,
            )
            .await
            .unwrap();
        s.send(()).unwrap();
        log_handle.await.unwrap();

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    #[tokio::test]
    async fn it_works() {}
}
